/**	 RELEITURA DO JOGO SOKOBAN ~ Trabalho final de Algoritmos e Programação ~ Ciência da Computação
Autor: Lucas S. Beiler (https://github.com/lucassbeiler) e Gustavo Martins (https://github.com/00-000)
Versão atual: v2.0.32.2
	**DESMARQUE A OPÇÃO "MODO DE EDIÇÃO RÁPIDA" NAS PROPRIEDADES DO CMD.EXE PARA EVITAR PROBLEMAS DURANTE A EXECUÇÃO**
   **TODO O CÓDIGO ABAIXO FOI DESENVOLVIDO E TESTADO USANDO O MICROSOFT VISUAL STUDIO 2019, PROBLEMAS DE COMPILAÇÃO EM OUTRAS IDEs/COMPILADORES** */

#include <iostream>
#include <conio.h>
#include <windows.h>
#include <time.h>

using namespace std;

void definirPosicaoElementosMenu(int x, int y) { //função usada para determinar as posições dos elementos do menu na tela
	HANDLE outp = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD coordenadas = { x, y };
	SetConsoleCursorPosition(outp, coordenadas);
}


int main() {
	int tempoFaseAtual = 0, multiplayer = 0, contadorPassos = 0, contadorEmpurra = 0, fase = 0, estadoFase[4], tempoFases[4], passosFases[4], caixasEmpurradasFases[4];
	string autor1, autor2, menu = "principal";
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO cInfo;

	GetConsoleCursorInfo(hConsole, &cInfo);
	cInfo.bVisible = false; //IMPEDE QUE O CURSOR DO CONSOLE FIQUE PISCANDO
	SetConsoleCursorInfo(hConsole, &cInfo);
	COORD coord;
	coord.X = 0;
	coord.Y = 0;

	CONSOLE_FONT_INFOEX cfi;
	cfi.cbSize = sizeof(cfi);
	cfi.dwFontSize.Y = 28; //escolha do tamanho da fonte
	SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi); // definição de fonte
	SetConsoleTextAttribute(hConsole, 9); // definição da cor azul do texto

   //PlaySound(TEXT("musica.wav"), NULL, SND_ASYNC | SND_LOOP | SND_NOSTOP);  // FEATURE DESCARTADA

	while (1) {
		cInfo.bVisible = false; // esconde o cursor branco do console
		POINT ponto;
		HWND hwnd = GetConsoleWindow();

		GetCursorPos(&ponto);
		ScreenToClient(hwnd, &ponto);

		//DESCOMENTE AS LINHAS ABAIXO PARA VER AS COORDENADAS DO MOUSE NA TELA (APENAS PARA DEBUGGING, MANTENHA-AS COMENTADAS EM OCASIÕES NORMAIS)
		//SetConsoleCursorPosition(hConsole, coord);
		//cout << "X: " << ponto.x << " Y: " << ponto.y;


		// CÓDIGO DOS MENUS:
		if (menu == "principal") { // condição usada para imprimir o menu principal
			definirPosicaoElementosMenu(24, 5);
			cout << "       |SOKOBAN.cpp|";

			definirPosicaoElementosMenu(27, 8);
			cout << "Jogar";
			cout << "\t Como jogar";

			definirPosicaoElementosMenu(27, 10);
			cout << "Equipe";
			cout << "\t Sair";

			definirPosicaoElementosMenu(32, 12);
			if (multiplayer == 1) {
				SetConsoleTextAttribute(hConsole, 2);
			}
			else { SetConsoleTextAttribute(hConsole, 12); }
			cout << "Multiplayer";
			SetConsoleTextAttribute(hConsole, 9);
		}
		if (GetKeyState(27) & 0x8000) { // ESC
			if (menu == "boletim") {
				menu = "fases_do_jogo"; // volta ao menu de escolha de fase 
				system("cls");
			}
			else {
				menu = "principal"; // volta ao menu principal
				system("cls");
			}
		}

		// ação de click do botão de ativar/desativar multiplayer
		if (menu == "principal" && ponto.y > 306 && ponto.y < 360 && ponto.x > 416 && ponto.x < 770 && GetAsyncKeyState(1) == -32767) {
			if (multiplayer == 1) {
				multiplayer = 0;
			}
			else {
				multiplayer = 1;
			}

		}

		//ação do botão jogar e impressão do menu de fases
		if (menu == "principal" && ponto.y > 195 && ponto.y < 250 && ponto.x > 335 && ponto.x < 500 && GetAsyncKeyState(1) == -32767 || menu == "fases_do_jogo") {
			menu = "fases"; // define menu atual como menu de seleção de fase
			system("cls");

			SetConsoleTextAttribute(hConsole, 9); // define cor padrão
			if (estadoFase[0] == 1) { SetConsoleTextAttribute(hConsole, 10); } //verde na linha seguinte caso fase 1 esteja concluída
			cout << "\n\n \t\t\t\t\tFase 1";  // imprime botão
			SetConsoleTextAttribute(hConsole, 9); // retorna à cor padrão
			if (estadoFase[1] == 1) { SetConsoleTextAttribute(hConsole, 10); } //verde na linha seguinte caso fase 2 esteja concluída
			cout << "\n\n \t\t\t\t\tFase 2"; // imprime botão
			SetConsoleTextAttribute(hConsole, 9); // retorna à cor padrão
			if (estadoFase[2] == 1) { SetConsoleTextAttribute(hConsole, 10); } // verde na linha seguinte caso fase 3 esteja concluída
			cout << "\n\n \t\t\t\t\tFase 3"; // imprime botão
			SetConsoleTextAttribute(hConsole, 9); // retorna à cor padrão
			if (estadoFase[3] == 1) { SetConsoleTextAttribute(hConsole, 10); } // verde na linha seguinte caso fase 4 esteja concluída
			cout << "\n\n \t\t\t\t\tFase 4"; // imprime botão
			SetConsoleTextAttribute(hConsole, 9); // retorna à cor padrão

			if (estadoFase[0] == 1 && estadoFase[1] == 1 && estadoFase[2] == 1 && estadoFase[3] == 1) { // caso todas as fases estejam em estado concluído...
				cout << "\n\n\n \t\t\t\t\tBoletim"; // ... mostra o botão.
			}
		}

		// botões para as fases 1~4 e para o boletim de resumo dos scores do jogador ao fim do jogo
		if (menu == "fases" && ponto.y > 44 && ponto.y < 84 && ponto.x > 527 && ponto.x < 716 && GetAsyncKeyState(1) == -32767) {
			fase = 1;
			menu = "jogo"; // vai à tela de jogo com fase = 1 (os ifs abaixo contém a mesma lógica)
		}if (menu == "fases" && ponto.y > 88 && ponto.y < 143 && ponto.x > 527 && ponto.x < 716 && GetAsyncKeyState(1) == -32767) {
			fase = 2;
			menu = "jogo";
		}if (menu == "fases" && ponto.y > 147 && ponto.y < 196 && ponto.x > 527 && ponto.x < 716 && GetAsyncKeyState(1) == -32767) {
			fase = 3;
			menu = "jogo";
		}if (menu == "fases" && ponto.y > 197 && ponto.y < 244 && ponto.x > 527 && ponto.x < 716 && GetAsyncKeyState(1) == -32767) {
			fase = 4;
			menu = "jogo";
		}if (menu == "fases" && ponto.y > 248 && ponto.y < 317 && ponto.x > 527 && ponto.x < 716 && GetAsyncKeyState(1) == -32767 && estadoFase[0] == 1 && estadoFase[1] == 1 && estadoFase[2] == 1 && estadoFase[3] == 1) {
			menu = "boletim";
			system("cls");
			SetConsoleTextAttribute(hConsole, 10);
			cout << "\n\n \t\t\tFase 1: " << tempoFases[0] << " segundos, " << passosFases[0] << " passos e caixas empurradas " << caixasEmpurradasFases[0] << "x";
			cout << "\n\n \t\t\tFase 2: " << tempoFases[1] << " segundos, " << passosFases[1] << " passos e caixas empurradas " << caixasEmpurradasFases[1] << "x";
			cout << "\n\n \t\t\tFase 3: " << tempoFases[2] << " segundos, " << passosFases[2] << " passos e caixas empurradas " << caixasEmpurradasFases[2] << "x";
			cout << "\n\n \t\t\tFase 4: " << tempoFases[3] << " segundos, " << passosFases[3] << " passos e caixas empurradas " << caixasEmpurradasFases[3] << "x";
			SetConsoleTextAttribute(hConsole, 9);
		}
		// decide quem vai aparecer primeiro na tela de créditos
		if ((time(NULL) % 10) >= 5) { autor1 = "Lucas S. Beiler"; autor2 = "Gustavo Martins"; }
		else if ((time(NULL) % 10) < 5) { autor1 = "Gustavo Martins"; autor2 = "Lucas S. Beiler"; }

		// ação do click no botão/tela de créditos
		if (ponto.y > 263 && ponto.y < 306 && ponto.x > 335 && ponto.x < 510 && GetAsyncKeyState(1) == -32767 && menu == "principal") {
			menu = "creditos";
			system("cls");
			cout << endl << endl << "\t  Desenvolvedores:\n";
			cout << "\t -------------------\n \t | " << autor1 << " | \n";
			cout << "\t | " << autor2 << " | \n \t -------------------";
		}

		// botão/ação sair
		if (ponto.y > 252 && ponto.y < 306 && ponto.x > 555 && ponto.x < 766 && GetAsyncKeyState(1) == -32767 && menu == "principal") {
			exit(0);
		}

		// ação do botão e tela de instruções sobre "Como Jogar"
		if (ponto.y > 195 && ponto.y < 247 && ponto.x > 556 && ponto.x < 796 && GetAsyncKeyState(1) == -32767 && menu == "principal") {
			menu = "instrucoes";
			system("cls");
			cout << endl << endl << "\t ---------------------\n \t | W:   subir \t    | \n";
			cout << "\t | S:   descer      | \n";
			cout << "\t | A:   esquerda    | \n";
			cout << "\t | D:   direita     |\n";
			cout << "\t | U:   puxar       |\n";
			cout << "\t | ESC: voltar      | \n \t --------------------- \n\n\n\n\n\n\n\n\n";
		}

		// CÓDIGO DO JOGO ABAIXO:

		// DEFINIÇÕES INICIAIS DOS MAPAS
		if (fase != 0) {
			time_t tempoestampa_inicial = time(NULL); // inicializa a variável que contém timestamp em UNIX epoch do momento de início do jogo
			system("cls");

			int fase1[11][14] = { {0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},{0, 0, 1, 2, 2, 5, 2, 1, 0, 0, 0, 0, 0, 0},{0, 0, 1, 2, 3, 2, 2, 1, 0, 0, 0, 0, 0, 0},{1, 1, 1, 1, 2, 3, 2, 1, 0, 0, 0, 0, 0, 0},{1, 2, 4, 1, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0},{1, 4, 4, 1, 2, 3, 1, 0, 0, 0, 0, 0, 0, 0},{1, 4, 4, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0},{1, 4, 4, 2, 3, 2, 2, 1, 0, 0, 0, 0, 0, 0},{1, 1, 1, 1, 3, 2, 2, 1, 0, 0, 0, 0, 0, 0},{0, 0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0},{0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} };

			int fase2[11][14] = { {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},{1, 1, 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0},{1, 2, 2, 1, 1, 3, 2, 1, 0, 0, 0, 0, 0, 0},{1, 5, 2, 2, 3, 2, 2, 1, 0, 0, 0, 0, 0, 0},{1, 2, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0},{1, 2, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0},{1, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},{1, 4, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0},{1, 4, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0},{1, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0},{1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0} };

			int fase3[11][14] = { {0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0},{1, 1, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0},{1, 4, 5, 3, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0},{1, 1, 1, 2, 3, 4, 1, 0, 0, 0, 0, 0, 0, 0},{1, 4, 1, 1, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0},{1, 2, 1, 2, 4, 2, 1, 1, 0, 0, 0, 0, 0, 0},{1, 3, 2, 2, 3, 3, 4, 1, 0, 0, 0, 0, 0, 0},{1, 2, 2, 2, 4, 2, 2, 1, 0, 0, 0, 0, 0, 0},{1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };

			int fase4[11][14] = { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0},{1, 4, 4, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1},{1, 4, 4, 2, 2, 1, 2, 3, 2, 2, 3, 2, 2, 1},{1, 4, 4, 2, 2, 1, 3, 1, 1, 1, 1, 2, 2, 1},{1, 4, 4, 2, 2, 2, 2, 5, 2, 1, 1, 2, 2, 1},{1, 4, 4, 2, 2, 1, 2, 1, 2, 2, 3, 2, 1, 1},{1, 1, 1, 1, 1, 1, 2, 1, 1, 3, 2, 3, 2, 1},{0, 0, 1, 2, 3, 2, 2, 3, 2, 3, 2, 3, 2, 1},{0, 0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1},{0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };


			int matriz[11][14]; // matriz genérica que receberá os valores da matriz da fase escolhida e todo o código do jogo trabalhará sobre ela

			for (int linhas = 0; linhas < 11; linhas++) { // percorre linhas
				for (int colunas = 0; colunas < 14; colunas++) { // percorre colunas
					if (fase == 1) {
						matriz[linhas][colunas] = fase1[linhas][colunas]; //atribui os valores da matriz da fase 1 à matriz genérica
					}
					else if (fase == 2) {
						matriz[linhas][colunas] = fase2[linhas][colunas]; //atribui os valores da matriz da fase 2 à matriz genérica
					}
					else if (fase == 3) {
						matriz[linhas][colunas] = fase3[linhas][colunas]; //atribui os valores da matriz da fase 3 à matriz genérica
					}
					else if (fase == 4) {
						matriz[linhas][colunas] = fase4[linhas][colunas]; //atribui os valores da matriz da fase 4 à matriz genérica
					}

					// DEFINIÇÃO DA POSIÇÃO DE SPAWN DO PLAYER 2 NO MODO MULTIJOGADOR
					if (fase == 1 && multiplayer == 1) {
						matriz[6][5] = 6;
					}if (fase == 2 && multiplayer == 1) {
						matriz[4][2] = 6;
					}if (fase == 3 && multiplayer == 1) {
						matriz[5][5] = 6;
					}if (fase == 4 && multiplayer == 1) {
						matriz[3][4] = 6;
					}
				}
			}

			// CÓDIGO DO JOGO E CONTROLES
			while (menu == "jogo" && fase != 0) {
				for (int linhas = 0; linhas < 11; linhas++) { // percorre linhas
					for (int colunas = 0; colunas < 14; colunas++) { // percorre colunas
						if (matriz[linhas][colunas] == 0 || matriz[linhas][colunas] == 2) { // verifica as posições dos espaços vazios
							cout << " "; // imprime os espaços vazios
						}
						else if (matriz[linhas][colunas] == 1) { // verifica as posições das paredes
							SetConsoleTextAttribute(hConsole, 7); 
							cout << char(177); //imprime as paredes
							SetConsoleTextAttribute(hConsole, 9); // definição da cor azul padrão
						}
						else if (matriz[linhas][colunas] == 4) {  // verifica as posições dos pontos de entrega/destinos
							SetConsoleTextAttribute(hConsole, 10); 
							cout << "."; // imprime-os
							SetConsoleTextAttribute(hConsole, 9); // definição da cor azul padrão
						}
						else if (matriz[linhas][colunas] == 3) {  // verifica as posições das caixas
							SetConsoleTextAttribute(hConsole, 14);
							cout << char(254); // imprime as caixas
							SetConsoleTextAttribute(hConsole, 9); // definição da cor azul padrão
						}
						else if (matriz[linhas][colunas] == 5) {  // verifica a posição do personagem
							SetConsoleTextAttribute(hConsole, 12);
							cout << char(221); // imprime o personagem
							SetConsoleTextAttribute(hConsole, 9); // definição da cor azul padrão
						}
						else if (matriz[linhas][colunas] == 6) {
							SetConsoleTextAttribute(hConsole, 3); 
							cout << char(221); // imprime o personagem
							SetConsoleTextAttribute(hConsole, 9); // definição da cor azul padrão
						}
					}
					cout << endl;
				}

				//VERIFICA SE TODAS AS CAIXAS FORAM ENTREGUES EM SUAS DEVIDAS POSIÇÕES, DÁ A VITÓRIA AO JOGADOR EM CASO AFIRMATIVO:
				if (fase == 1 && matriz[7][1] == 3 && matriz[7][2] == 3 && matriz[6][1] == 3 && matriz[6][2] == 3 && matriz[5][1] == 3 && matriz[5][2] == 3 && matriz[4][2] == 3 || fase == 2 && matriz[7][1] == 3 && matriz[8][1] == 3 || fase == 3 && matriz[2][1] == 3 && matriz[3][5] == 3 && matriz[4][1] == 3 && matriz[5][4] == 3 && matriz[6][6] == 3 && matriz[7][4] == 3 || fase == 4 && matriz[1][1] == 3 && matriz[1][2] == 3 && matriz[2][1] == 3 && matriz[2][2] == 3 && matriz[3][1] == 3 && matriz[3][2] == 3 && matriz[4][1] == 3 && matriz[4][2] == 3 && matriz[5][1] == 3 && matriz[5][2] == 3) {
					if (fase == 1) { // se fase == n (apenas esse if será comentado pois os abaixo aplicam a mesma lógica)
						estadoFase[0] = 1; // define fase como concluída
						tempoFases[0] = tempoFaseAtual; // guarda o tempo levado nessa fase
						caixasEmpurradasFases[0] = contadorEmpurra; // guarda a quantidade de vezes que caixas foram empurradas nessa fase
						passosFases[0] = contadorPassos; // guarda a quantidade de passos dados na fase
					}
					else if (fase == 2) {
						estadoFase[1] = 1;
						tempoFases[1] = tempoFaseAtual;
						caixasEmpurradasFases[1] = contadorEmpurra;
						passosFases[1] = contadorPassos;
					}
					else if (fase == 3) {
						estadoFase[2] = 1;
						tempoFases[2] = tempoFaseAtual;
						caixasEmpurradasFases[2] = contadorEmpurra;
						passosFases[2] = contadorPassos;
					}
					else if (fase == 4) {
						estadoFase[3] = 1;
						tempoFases[3] = tempoFaseAtual;
						caixasEmpurradasFases[3] = contadorEmpurra;
						passosFases[3] = contadorPassos;
					}

					Sleep(420);
					system("cls");
					definirPosicaoElementosMenu(14, 3);
					if (estadoFase[0] == 1 && estadoFase[1] == 1 && estadoFase[2] == 1 && estadoFase[3] == 1) { // dá a vitória ao jogador pela fase e pelo fim do jogo quando a última das fases é concluída
						cout << "Fase terminada! Levou " << time(NULL) - tempoestampa_inicial << " segundos, deu " << contadorPassos << " passos e empurrou caixas " << contadorEmpurra << "x";
						Sleep(1469);
						system("cls");
						definirPosicaoElementosMenu(14, 3);
						cout << "Todas as fases completas. Fim de jogo!";
					}
					else { // simplesmente parabeniza o jogador pelo fim de uma fase qualquer
						cout << "Fase terminada! Levou " << time(NULL) - tempoestampa_inicial << " segundos, deu " << contadorPassos << " passos e empurrou caixas " << contadorEmpurra << "x";
					}
					Sleep(2666);
					system("cls");
					fase = 0; // sai de qualquer fase
					system("cls");
					menu = "fases_do_jogo"; // volta ao menu de fases
					contadorPassos = 0; // zera o contador para que ele esteja zerado na próxima fase
					contadorEmpurra = 0; // zera o contador para que ele se encontre zerado na próxima fase
				}

				// CÓDIGOS PARA CONTROLE
				if (_kbhit()) {
					char tecla = _getch();
					for (int linhas = 0; linhas < 11; linhas++) { // percorre as linhas da matriz
						for (int colunas = 0; colunas < 14; colunas++) { // percorre as colunas da matriz

							//	CÓDIGO DO DESFAZEDOR DE MOVIMENTOS/PUXADOR DE CAIXAS NAS CONDIÇÕES ABAIXO
							if (matriz[linhas][colunas] == 3 && matriz[linhas + 1][colunas] == 5 && (matriz[linhas - 1][colunas] == 1 || matriz[linhas - 1][colunas] == 3) && matriz[linhas + 2][colunas] != 1 && matriz[linhas + 2][colunas] != 3) {
								if (GetKeyState('u') & 0x8000 || GetKeyState('U') & 0x8000) {
									matriz[linhas][colunas] = 2; // esvazia a posição da caixa
									matriz[linhas + 1][colunas] = 3; // move a caixa pra baixo
									matriz[linhas + 2][colunas] = 5; // move o personagem pra baixo
									//PUXA CAIXA DE CIMA PRA BAIXO CASO ESTEJA ENCOSTADA EM UMA PAREDE (DESFAZ 'W')
								}
							}
							else if (matriz[linhas][colunas] == 3 && matriz[linhas - 1][colunas] == 5 && (matriz[linhas + 1][colunas] == 1 || matriz[linhas + 1][colunas] == 3) && matriz[linhas - 2][colunas] != 1 && matriz[linhas - 2][colunas] != 3) {
								if (GetKeyState('u') & 0x8000 || GetKeyState('U') & 0x8000) {
									matriz[linhas][colunas] = 2; // esvazia a posição da caixa
									matriz[linhas - 1][colunas] = 3; // move a caixa pra cima
									matriz[linhas - 2][colunas] = 5; // move o personagem pra cima
									//PUXA CAIXA DE BAIXO PRA CIMA CASO ESTEJA ENCOSTADA EM UMA PAREDE (DESFAZ 'S')
								}
							}
							else if (matriz[linhas][colunas] == 3 && matriz[linhas][colunas - 1] == 5 && (matriz[linhas][colunas + 1] == 1 || matriz[linhas][colunas + 1] == 3) && matriz[linhas][colunas - 2] != 1 && matriz[linhas][colunas - 2] != 3) {
								if (GetKeyState('u') & 0x8000 || GetKeyState('U') & 0x8000) {
									matriz[linhas][colunas] = 2; // esvazia a posição da caixa
									matriz[linhas][colunas - 1] = 3; // move a caixa pra esquerda
									matriz[linhas][colunas - 2] = 5; // move o personagem pra esquerda
									//PUXA CAIXA DA DIREITA PRA ESQUERDA CASO ESTEJA ENCOSTADA EM UMA PAREDE (DESFAZ 'D')
								}
							}
							else if (matriz[linhas][colunas] == 3 && matriz[linhas][colunas + 1] == 5 && (matriz[linhas][colunas - 1] == 1 || matriz[linhas][colunas - 1] == 3) && matriz[linhas][colunas + 2] != 1 && matriz[linhas][colunas + 2] != 3) {
								if (GetKeyState('u') & 0x8000 || GetKeyState('U') & 0x8000) {
									matriz[linhas][colunas] = 2; // esvazia a posição da caixa
									matriz[linhas][colunas + 1] = 3; // move a caixa pra direita
									matriz[linhas][colunas + 2] = 5; // move o personagem pra direita
									//PUXA CAIXA DA ESQUERDA PRA DIREITA CASO ESTEJA ENCOSTADA EM UMA PAREDE (DESFAZ 'A')
								}
							}

							if (multiplayer == 1) {
								//	CÓDIGO DO DESFAZEDOR DE MOVIMENTOS/PUXADOR DE CAIXAS NAS CONDIÇÕES ABAIXO
								if (matriz[linhas][colunas] == 3 && matriz[linhas + 1][colunas] == 6 && (matriz[linhas - 1][colunas] == 1 || matriz[linhas - 1][colunas] == 3) && matriz[linhas + 2][colunas] != 1 && matriz[linhas + 2][colunas] != 3) {
									if (GetKeyState('u') & 0x8000 || GetKeyState('U') & 0x8000) {
										matriz[linhas][colunas] = 2; // esvazia a posição da caixa
										matriz[linhas + 1][colunas] = 3; // move a caixa pra baixo
										matriz[linhas + 2][colunas] = 6; // move o personagem pra baixo
										//PUXA CAIXA DE CIMA PRA BAIXO CASO ESTEJA ENCOSTADA EM UMA PAREDE (DESFAZ 'W')
									}
								}
								else if (matriz[linhas][colunas] == 3 && matriz[linhas - 1][colunas] == 6 && (matriz[linhas + 1][colunas] == 1 || matriz[linhas + 1][colunas] == 3) && matriz[linhas - 2][colunas] != 1 && matriz[linhas - 2][colunas] != 3) {
									if (GetKeyState('u') & 0x8000 || GetKeyState('U') & 0x8000) {
										matriz[linhas][colunas] = 2; // esvazia a posição da caixa
										matriz[linhas - 1][colunas] = 3; // move a caixa pra cima
										matriz[linhas - 2][colunas] = 6; // move o personagem pra cima
										//PUXA CAIXA DE BAIXO PRA CIMA CASO ESTEJA ENCOSTADA EM UMA PAREDE (DESFAZ 'S')
									}
								}
								else if (matriz[linhas][colunas] == 3 && matriz[linhas][colunas - 1] == 6 && (matriz[linhas][colunas + 1] == 1 || matriz[linhas][colunas + 1] == 3) && matriz[linhas][colunas - 2] != 1 && matriz[linhas][colunas - 2] != 3) {
									if (GetKeyState('u') & 0x8000 || GetKeyState('U') & 0x8000) {
										matriz[linhas][colunas] = 2; // esvazia a posição da caixa
										matriz[linhas][colunas - 1] = 3; // move a caixa pra esquerda
										matriz[linhas][colunas - 2] = 6; // move o personagem pra esquerda
										//PUXA CAIXA DA DIREITA PRA ESQUERDA CASO ESTEJA ENCOSTADA EM UMA PAREDE (DESFAZ 'D')
									}
								}
								else if (matriz[linhas][colunas] == 3 && matriz[linhas][colunas + 1] == 6 && (matriz[linhas][colunas - 1] == 1 || matriz[linhas][colunas - 1] == 3) && matriz[linhas][colunas + 2] != 1 && matriz[linhas][colunas + 2] != 3) {
									if (GetKeyState('u') & 0x8000 || GetKeyState('U') & 0x8000) {
										matriz[linhas][colunas] = 2; // esvazia a posição da caixa
										matriz[linhas][colunas + 1] = 3; // move a caixa pra direita
										matriz[linhas][colunas + 2] = 6; // move o personagem pra direita
										//PUXA CAIXA DA ESQUERDA PRA DIREITA CASO ESTEJA ENCOSTADA EM UMA PAREDE (DESFAZ 'A')
									}
								}
							}


							// a condição abaixo serve pra fazer com que os pontos de entrega da caixa (representados por 4 na matriz) não sumam definitivamente a partir do momento em que o personagem (5) passa por eles e vai embora
							if (fase == 1 && fase1[linhas][colunas] == 4 && matriz[linhas][colunas] == 2 || fase == 2 && fase2[linhas][colunas] == 4 && matriz[linhas][colunas] == 2 || fase == 3 && fase3[linhas][colunas] == 4 && matriz[linhas][colunas] == 2 || fase == 4 && fase4[linhas][colunas] == 4 && matriz[linhas][colunas] == 2) {
								matriz[linhas][colunas] = 4; // redefinição dos valores daquelas posições a 4 para que ele seja redesenhado
							}

							if (GetKeyState('W') & 0x8000 || GetKeyState('w') & 0x8000) {
								if (matriz[linhas][colunas] == 5 && matriz[linhas - 2][colunas] != 1 && matriz[linhas - 2][colunas] != 6) {
									if (matriz[linhas - 1][colunas] == 3 && matriz[linhas - 2][colunas] != 3 && matriz[linhas - 2][colunas] != 1) {
										matriz[linhas - 1][colunas] = 5; // movimenta o personagem à posição onde a caixa se encontra
										matriz[linhas - 2][colunas] = 3; // empurra a caixa pra cima
										contadorEmpurra++; // incrementa o contador de empurrões dados em caixas
									}
								}if (matriz[linhas][colunas] == 5 && matriz[linhas - 1][colunas] != 1 && matriz[linhas - 1][colunas] != 3 && matriz[linhas - 1][colunas] != 6) {
										matriz[linhas][colunas] = 2; // esvazia a posição atual do personagem
										matriz[--linhas][colunas] = 5; // move o personagem acima do ponto anterior
										contadorPassos++; // incrementa o contador de passos
								}
							}



							if (GetKeyState('S') & 0x8000 || GetKeyState('s') & 0x8000) {
								if (matriz[linhas][colunas] == 5 && matriz[linhas + 2][colunas] != 1) {
									if (matriz[linhas + 1][colunas] == 3 && matriz[linhas + 2][colunas] != 3 && matriz[linhas + 2][colunas] != 1 && matriz[linhas + 2][colunas] != 6) {
										matriz[linhas + 1][colunas] = 5; // movimenta o personagem à posição onde a caixa se encontra
										matriz[linhas + 2][colunas] = 3; // empurra a caixa pra baixo
										contadorEmpurra++; // incrementa o contador de empurrões dados em caixas
									}
								}if (matriz[linhas][colunas] == 5 && matriz[linhas + 1][colunas] != 1 && matriz[linhas + 1][colunas] != 3 && matriz[linhas + 1][colunas] != 6) {
										matriz[linhas][colunas] = 2; // esvazia a posição atual do personagem
										matriz[++linhas][colunas] = 5; // move o personagem abaixo do ponto anterior
										contadorPassos++; // incrementa o contador de passos
									}
								}

							if (GetKeyState('A') & 0x8000 || GetKeyState('a') & 0x8000) {
								if (matriz[linhas][colunas] == 5 && matriz[linhas][colunas - 2] != 1) {
									if (matriz[linhas][colunas - 1] == 3 && matriz[linhas][colunas - 2] != 3 && matriz[linhas][colunas - 2] != 1 && matriz[linhas][colunas - 2] != 6) {
										matriz[linhas][colunas - 1] = 5; // movimenta o personagem à posição onde a caixa se encontra
										matriz[linhas][colunas - 2] = 3; // empurra a caixa à esquerda
										contadorEmpurra++; // incrementa a quantidade de empurrões dados em caixas
									}
								}if (matriz[linhas][colunas] == 5 && matriz[linhas][colunas - 1] != 1 && matriz[linhas][colunas - 1] != 3 && matriz[linhas][colunas - 1] != 6) {
										matriz[linhas][colunas] = 2; // esvazia a posição atual do personagem
										matriz[linhas][--colunas] = 5; // move o personagem à esquerda do ponto anterior
										contadorPassos++; // incrementa o contador de passos
								}
							}if (GetKeyState('D') & 0x8000 || GetKeyState('d') & 0x8000) {
								if (matriz[linhas][colunas] == 5 && matriz[linhas][colunas + 2] != 1) {
									if (matriz[linhas][colunas + 1] == 3 && matriz[linhas][colunas + 2] != 3 && matriz[linhas][colunas + 2] != 1 && matriz[linhas][colunas + 2] != 6) {
										matriz[linhas][colunas + 1] = 5; // movimenta o personagem à posição onde a caixa se encontra
										matriz[linhas][colunas + 2] = 3; // empurra a caixa à direita
										contadorEmpurra++; // incrementa a quantidade de empurrões dados em caixas
									}
								}if (matriz[linhas][colunas] == 5 && matriz[linhas][colunas + 1] != 1 && matriz[linhas][colunas + 1] != 3 && matriz[linhas][colunas + 1] != 6) { // mover personagem à direita
										matriz[linhas][colunas] = 2; // esvazia a posição atual do personagem
										matriz[linhas][++colunas] = 5; // move o personagem à direita do ponto anterior
										contadorPassos++; // incrementa a quantidade de passos dados
								}
							}if (GetKeyState(27) & 0x8000) { // ESC
								fase = 0; // sai de qualquer fase
								menu = "fases_do_jogo"; // volta ao menu de fases
								system("cls");
								contadorPassos = 0; // zera contador de passos
								contadorEmpurra = 0; // zera contador de empurrões em caixas
							}
						}
					}
					cout << "Passos: " << contadorPassos;
					cout << " | Empurradas: " << contadorEmpurra;
				}
				tempoFaseAtual = time(NULL) - tempoestampa_inicial; // subtrai UNIX time atual por UNIX time do momento do início do jogo para determinar o tempo passado
				cout << endl << "Tempo de jogo: " << tempoFaseAtual << " segundos";
				SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); // evita que a tela fique piscando durante a impressão de novos frames

				// CÓDIGOS PARA CONTROLE DO PERSONAGEM 2 DO MODO MULTIJOGADOR
				if (_kbhit()) {
					char tecla = _getch();
					for (int linhas = 0; linhas < 11; linhas++) { // percorre as linhas da matriz
						for (int colunas = 0; colunas < 14; colunas++) { // percorre as colunas da matriz
							if (multiplayer == 1) {
								if (GetKeyState(38) & 0x8000) {
									if (matriz[linhas][colunas] == 6 && matriz[linhas - 2][colunas] != 1 && matriz[linhas - 2][colunas] != 5) {
										if (matriz[linhas - 1][colunas] == 3 && matriz[linhas - 2][colunas] != 3 && matriz[linhas - 2][colunas] != 1 && matriz[linhas - 2][colunas] != 5) {
											matriz[linhas - 1][colunas] = 6; // movimenta o personagem à posição onde a caixa se encontra
											matriz[linhas - 2][colunas] = 3; // empurra a caixa pra cima
											contadorEmpurra++; // incrementa o contador de empurrões dados em caixas
										}
									}if (matriz[linhas][colunas] == 6 && matriz[linhas - 1][colunas] != 1 && matriz[linhas - 1][colunas] != 3 && matriz[linhas - 1][colunas] != 5) {
										matriz[linhas][colunas] = 2; // esvazia a posição atual do personagem
										matriz[--linhas][colunas] = 6; // move o personagem acima do ponto anterior
										contadorPassos++; // incrementa o contador de passos
									}
								}

								if (GetKeyState(40) & 0x8000) {
									if (matriz[linhas][colunas] == 6 && matriz[linhas + 2][colunas] != 1) {
										if (matriz[linhas + 1][colunas] == 3 && matriz[linhas + 2][colunas] != 3 && matriz[linhas + 2][colunas] != 1 && matriz[linhas + 2][colunas] != 5) {
											matriz[linhas + 1][colunas] = 6; // movimenta o personagem à posição onde a caixa se encontra
											matriz[linhas + 2][colunas] = 3; // empurra a caixa pra baixo
											contadorEmpurra++; // incrementa o contador de empurrões dados em caixas
										}
									}if (matriz[linhas][colunas] == 6 && matriz[linhas + 1][colunas] != 1 && matriz[linhas + 1][colunas] != 3 && matriz[linhas + 1][colunas] != 5) {
										matriz[linhas][colunas] = 2; // esvazia a posição atual do personagem
										matriz[++linhas][colunas] = 6; // move o personagem abaixo do ponto anterior
										contadorPassos++; // incrementa o contador de passos

									}
								}

								if (GetKeyState(37) & 0x8000) {
									if (matriz[linhas][colunas] == 6 && matriz[linhas][colunas - 2] != 1) {
										if (matriz[linhas][colunas - 1] == 3 && matriz[linhas][colunas - 2] != 3 && matriz[linhas][colunas - 2] != 1 && matriz[linhas][colunas - 2] != 5) {
											matriz[linhas][colunas - 1] = 6; // movimenta o personagem à posição onde a caixa se encontra
											matriz[linhas][colunas - 2] = 3; // empurra a caixa à esquerda
											contadorEmpurra++; // incrementa a quantidade de empurrões dados em caixas
										}
									}if (matriz[linhas][colunas] == 6 && matriz[linhas][colunas - 1] != 1 && matriz[linhas][colunas - 1] != 3 && matriz[linhas][colunas - 1] != 5) {
										matriz[linhas][colunas] = 2; // esvazia a posição atual do personagem
										matriz[linhas][--colunas] = 6; // move o personagem à esquerda do ponto anterior
										contadorPassos++; // incrementa o contador de passos
									}
								}


								if (GetKeyState(39) & 0x8000) {
									if (matriz[linhas][colunas] == 6 && matriz[linhas][colunas + 2] != 1) {
										if (matriz[linhas][colunas + 1] == 3 && matriz[linhas][colunas + 2] != 3 && matriz[linhas][colunas + 2] != 1 && matriz[linhas][colunas + 2] != 5) {
											matriz[linhas][colunas + 1] = 6; // movimenta o personagem à posição onde a caixa se encontra
											matriz[linhas][colunas + 2] = 3; // empurra a caixa à direita
											contadorEmpurra++; // incrementa a quantidade de empurrões dados em caixas
										}
									}if (matriz[linhas][colunas] == 6 && matriz[linhas][colunas + 1] != 1 && matriz[linhas][colunas + 1] != 3 && matriz[linhas][colunas + 1] != 5) { // mover personagem à direita
										matriz[linhas][colunas] = 2; // esvazia a posição atual do personagem
										matriz[linhas][++colunas] = 6; // move o personagem à direita do ponto anterior
										contadorPassos++; // incrementa a quantidade de passos dados

									}
								}
							}
						}
					}
				}
			}
		}
	}
}
